package com.learnlogincheck.learnlogincheck.shiro;



import com.learnlogincheck.learnlogincheck.daoImpl.loginImpl;
import com.learnlogincheck.learnlogincheck.jwt.jwtToken;
import com.learnlogincheck.learnlogincheck.utils.RedisUtil;
import com.learnlogincheck.learnlogincheck.utils.jwtUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashSet;
import java.util.Set;
@Component
public class CustomRealm extends AuthorizingRealm {
    HttpServletRequest request;
    HttpServletResponse response;
    private loginImpl logins;
    @Autowired
    private void setUserMapper(loginImpl logins) {
        this.logins = logins;
    }
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private com.learnlogincheck.learnlogincheck.daoImpl.tockenImpl tockenImpl;

    /**
     * 必须重写此方法，不然会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof jwtToken;
    }


    /**
     * 获取身份验证信息
     * Shiro中，最终是通过 Realm 来获取应用程序中的用户、角色及权限信息的。
     *
     * @param authenticationToken 用户身份信息 token
     * @return 返回封装了用户信息的 AuthenticationInfo 实例
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("————身份认证方法————");
        String token = (String) authenticationToken.getCredentials();
        // 解密获得username，用于和数据库进行对比
        String username = jwtUtil.getUsername(token);
        //首先先去判断自动生成的token是否已经过期  如果已经过期去redis里面判断是否过期
         if(!jwtUtil.verify(token, username)){
             if(redisUtil.hasKey(username)==false){
                 //如果redis里面也是空的提示重新登录  有可能tocken过期 就在数据库里面查询
                 if(StringUtils.isBlank(tockenImpl.selectToken(username))){
                     throw new AuthenticationException("您的登录已过期，请您重新登录！");
                 }else {
                         //判断数据库
                         if(StringUtils.isNotBlank(tockenImpl.selectToken(username))){
                                 //如果数据库不是空的 判断该用户是否存在
                                 String password = logins.getPassword(username);
                                 if (password == null) {
                                     throw new AuthenticationException("该用户不存在！");
                                 }
                                 //重新生成token 放进redis 每次请求方法返回给前端重置token
                                 redisUtil.del(username);
                                 tockenImpl.deTocken(username);
                                 redisUtil.set(username,jwtUtil.createToken(username),360);
                                 tockenImpl.inTocken(username,jwtUtil.createToken(username));
                         }

                     }

                 } else {
                 if(redisUtil.get(username).toString().equals(token)) {
                     String password = logins.getPassword(username);
                     if (password == null) {
                         throw new AuthenticationException("该用户不存在！");
                     }
                 }else{
                     throw new AuthenticationException("用户认证失败");
                 }
             }
             }


        // 拿到视图解析器
           /*    if (username == null || !jwtUtil.verify(token, username)) {
                    throw new AuthenticationException("token认证失败！");
                }*/
       //如果自动生成的token不是空的 判断该用户是否存在
        String password = logins.getPassword(username);
        if (password == null) {
            throw new AuthenticationException("该用户不存在！");
        }
        return new SimpleAuthenticationInfo(token, token, "MyRealm");
        //从Shiro中获取用户
        //UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
     /* // 从数据库获取对应用户名密码的用户
        String password = logins.getPassword(token.getUsername());
        if (null == password) {
            throw new AccountException("用户名不正确");
        } else if (!password.equals(new String((char[]) token.getCredentials()))) {
            throw new AccountException("密码不正确");
        }
        return new SimpleAuthenticationInfo(token.getPrincipal(), password, getName());*/


    }


    /**
     * 获取授权信息
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("————权限认证————");
        //单独shiro认证时
      /*  String username = (String) SecurityUtils.getSubject().getPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //获得该用户角色
        String role = logins.getRole(username);
        //如果一个用户有多个权限应该是List接受循环遍历
        Set<String> set = new HashSet<>();
        //需要将 role 封装到 Set 作为 info.setRoles() 的参数
        set.add(role);
        //设置该用户拥有的角色
        info.setRoles(set);*/

      //shiro+jwt方式
        Set<String> roleSet = new HashSet<>();
        Set<String> permissionSet = new HashSet<>();
        //获取用户名
        String username = jwtUtil.getUsername(principalCollection.toString());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //获得该用户角色
        String role = logins.getRole(username);
        //每个角色拥有默认的权限
        String rolePermission = logins.getPermiss(username);
        //每个用户可以设置新的权限
        //String permission = logins.getPermission(username);
        roleSet.add(role);
        permissionSet.add(rolePermission);
        info.setRoles(roleSet);
        info.setStringPermissions(permissionSet);
        return info;
    }
}
